"""
"""
import unittest as ut
import sys

import basicVdsTest as vdst
import vdsClient as vdsc
from storageConnectionTestUtils import eStorageType, disconnectFromStorage, connectToStorage, validateConnections, CONNECTIONS_OPTION_DEFAULT
from storageDomainTestUtils import eDomainClass, generateDomainTargets, destroyDomainTargets
from confUtils import Validate
from enum import Enum
from agentUtils import connectAgent
from testUtils import cleanVdsm

from vdsClient import BLANK_UUID

__commonConfig__ = {
    "VdsUri1" : {"default" : "http://server:54321"},
    "Connections" : {"default" : CONNECTIONS_OPTION_DEFAULT, "validator" : validateConnections},
    "DomainClass1" : {"default" : "data", "validator" : eDomainClass.parse},
    "Domain1" : {"default" : "GUID, GUID", "validator" : Validate.list},
    "StorageType1": {"default" : "nfs", "validator" : eStorageType.parse},
    "DomainClass2" : {"default" : "data", "validator" : eDomainClass.parse},
    "Domain2" : {"default" : "GUID, GUID", "validator" : Validate.list},
    "StorageType2": {"default" : "nfs", "validator" : eStorageType.parse},
    "DomainClass3" : {"default" : "data", "validator" : eDomainClass.parse},
    "Domain3" : {"default" : "GUID, GUID", "validator" : Validate.list},
    "StorageType3": {"default" : "nfs", "validator" : eStorageType.parse},
    "HostID1" : {"default" : 7, "validator" : Validate.int},
    "Pool1Key" : {"default" : "NFSKEY"}
}

class ExportTestCaseBase(vdst.BasicVDSTest):
    #For convenience. I didn't put it in the base class because I didn't want to commit.
    mycfg = property(lambda self: self.cfg[self.__class__.__name__])
    @classmethod
    def getConfigTemplate(cls):
        return {cls.__name__ : __commonConfig__}

    def setUp(self):
        #Setup client
        self.client = vdsc.VDSClient()
        self.client.setURI(self.mycfg["VdsUri1"])
        self.agent = connectAgent(self.mycfg["VdsUri1"])

        #Make sure env is clean
        resp = self.assertVdscOK(self.client.getConnectedStoragePoolsList())
        self.assertTrue(len(resp['poollist']) == 0, "VDSM is connected to a pool. Dirty env. Bailing out.")

        #Handle storage configuration
        connectToStorage(self.client, self.mycfg["Connections"])
        self.domainTarget1, self.domainTarget2, self.domainTarget3 = generateDomainTargets(self.client,
                    self.mycfg["Connections"], [self.mycfg["Domain1"], self.mycfg["Domain2"], self.mycfg["Domain3"]])

        #setup test variables
        self.sdUUID1 = self.client.newUUID()
        self.sdUUID2 = self.client.newUUID()
        self.expSdUUID = self.client.newUUID()
        self.spUUID = self.client.newUUID()

        #Create the tmp domains
        self.assertVdscOK(
            self.client.createStorageDomain(self.mycfg["StorageType1"], self.sdUUID1,
                "Storage Domain", self.domainTarget1, self.mycfg["DomainClass1"]
            )
        )

        self.assertVdscOK(
            self.client.createStorageDomain(self.mycfg["StorageType2"], self.sdUUID2,
                "Storage Domain", self.domainTarget2, self.mycfg["DomainClass2"]
            )
        )

        self.assertVdscOK(
            self.client.createStorageDomain(self.mycfg["StorageType3"], self.expSdUUID,
                "Export Domain", self.domainTarget3, vdsc.BACKUP_DOMAIN
            )
        )

        #Create tmp pool
        self.assertVdscOK(
            self.client.createStoragePool(self.spUUID, "Swimming Pool", self.sdUUID1, [self.sdUUID1, self.sdUUID2], 1)
            )

        self.assertVdscOK(
            self.client.connectStoragePool(self.spUUID, self.mycfg["HostID1"], self.mycfg["Pool1Key"])
            )

        taskid = self.assertVdscOK(self.client.spmStart(self.spUUID, -1, -1, -1, False))['uuid']
        self.assertVdscTaskOK(self.client, taskid)

        self.assertVdscOK(
            self.client.activateStorageDomain(self.sdUUID1, self.spUUID)
        )

        self.assertVdscOK(
            self.client.activateStorageDomain(self.sdUUID2, self.spUUID)
        )

        self.baseVolUUID = vdsc.VDSClient.newUUID()
        self.baseImgUUID = vdsc.VDSClient.newUUID()
        self.templateVolUUID = vdsc.VDSClient.newUUID()
        self.templateImgUUID = vdsc.VDSClient.newUUID()
        self.templateVmUUID = vdsc.VDSClient.newUUID()
        self.newVolUUID = vdsc.VDSClient.newUUID()
        self.newImgUUID = vdsc.VDSClient.newUUID()
        self.newVmUUID = vdsc.VDSClient.newUUID()

        self.assertVdscOK(
            self.client.attachStorageDomain(self.expSdUUID, self.spUUID)
            )

        self.assertVdscOK(
            self.client.activateStorageDomain(self.expSdUUID, self.spUUID)
        )

    def _createTemplate(self, imageFormat=vdsc.COW_FORMAT, formatImage=True):
        volsize = str(100 * (2 ** 20))

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID1, self.spUUID, self.baseImgUUID, volsize,
                imageFormat, vdsc.PREALLOCATED_VOL, "DATA", self.baseVolUUID, "Base volume")
        )

        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID1, self.spUUID, self.baseImgUUID, self.baseVolUUID)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID1, self.spUUID, self.baseImgUUID, self.baseVolUUID)
        )

        if formatImage:
            self.agent.formatDiskImage(volPath, [(10, "ext2")], imageFormat)
            self.agent.checkDiskImageSignature(volPath, imageFormat)

        self.assertVdscOK(
            self.client.teardownVolume(self.sdUUID1, self.spUUID, self.baseImgUUID, self.baseVolUUID)
        )

        taskID = self.assertVdscOK(
            self.client.copyImage(self.sdUUID1, self.spUUID, self.templateVmUUID, self.baseImgUUID,
                self.baseVolUUID, self.templateImgUUID, self.templateVolUUID, "Template of the beast", self.sdUUID1,
                vdsc.SHARED_VOL, vdsc.COW_FORMAT, vdsc.PREALLOCATED_VOL, blocked = False)
        )['uuid']
        self.assertVdscTaskOK(self.client, taskID, 999)

    def _createImageFromTemplate(self):
        volsize = str(100 * (2 ** 20))

        self.assertVdscOK(
            self.client.createVolume(self.sdUUID1, self.spUUID, self.newImgUUID, volsize,
                vdsc.COW_FORMAT, vdsc.SPARSE_VOL, "DATA", self.newVolUUID, "Base volume",
                self.templateImgUUID, self.templateVolUUID)
        )

    def _createBaseStack(self, imageFormat=vdsc.COW_FORMAT, formatImage=True):
        self._createTemplate(imageFormat, formatImage)
        self._createImageFromTemplate()

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID1, self.spUUID, self.newImgUUID, self.newVolUUID)
        )

        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID1, self.spUUID, self.newImgUUID, self.newVolUUID)
        )['path']

        self.assertTrue(self.agent.checkDiskImageSignature(volPath, vdsc.COW_FORMAT))

        self.assertVdscOK(
            self.client.teardownVolume(self.sdUUID1, self.spUUID, self.newImgUUID, self.newVolUUID)
        )

    def tearDown(self):
        #print "CLICKCKCCCK"
        #sys.stdin.read(1)
        #print "CLEANENENENEN"
        cleanVdsm(self.client, self.mycfg["HostID1"], self.mycfg["Connections"])

class ImageExportTests(ExportTestCaseBase):
    def _export(self, collapse, imageFormat):
       # Export for the first time.
        taskID = None
        if not collapse:
            taskID = self.assertVdscOK(
                self.client.moveImage(self.spUUID, self.sdUUID1, self.expSdUUID, self.newImgUUID,
                self.newVmUUID, vdsc.COPYOP, False, False, blocked=False)
            )['uuid']
        else:
            taskID = self.assertVdscOK(
                self.client.copyImage(self.sdUUID1, self.spUUID, self.templateVmUUID, self.newImgUUID,
                    self.newVolUUID, self.newImgUUID, self.newVolUUID, "I AM A COPY", self.expSdUUID,
                    vdsc.LEAF_VOL, imageFormat, vdsc.PREALLOCATED_VOL, blocked=False)
            )['uuid']

        self.assertVdscTaskOK(self.client, taskID, 999)

    def _exportAgain(self, collapse, force, imageFormat):
        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID1, self.spUUID, self.newImgUUID, self.newVolUUID)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.sdUUID1, self.spUUID, self.newImgUUID, self.newVolUUID)
        )

        self.agent.checkDiskImageSignature(volPath, imageFormat)
        self.agent.addFileToDiskImage(volPath, 1, "/I.HATE.THIS", "Can you tell me where my country lies", imageFormat)

        self.assertVdscOK(
            self.client.teardownVolume(self.sdUUID1, self.spUUID, self.newImgUUID, self.newVolUUID)
        )

        taskID = None
        if not collapse:
            taskID = self.assertVdscOK(
                self.client.moveImage(self.spUUID, self.sdUUID1, self.expSdUUID, self.newImgUUID,
                self.newVmUUID, vdsc.COPYOP, False, force, blocked = False)
            )['uuid']
        else:
            taskID = self.assertVdscOK(
                self.client.copyImage(self.sdUUID1, self.spUUID, self.templateVmUUID, self.newImgUUID,
                    self.newVolUUID, self.newImgUUID, self.newVolUUID, "I AM A COPY", self.expSdUUID,
                    vdsc.LEAF_VOL, imageFormat, vdsc.PREALLOCATED_VOL, False, force, blocked = False)
            )['uuid']


        if force:
            self.assertVdscTaskOK(self.client, taskID, 999)
        else:
            self.assertVdscTaskFail(self.client, taskID, 999)

    def _exportTemplate(self):
        self.assertVdscOK(
            self.client.moveImage(self.spUUID, self.sdUUID1, self.expSdUUID, self.templateImgUUID,
            self.templateVmUUID, vdsc.COPYOP, False, False)
        )

    def _testImage(self, imageFormat):
        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.expSdUUID, self.spUUID, self.newImgUUID, self.newVolUUID)
        )['path']

        self.assertVdscOK(
            self.client.prepareVolume(self.expSdUUID, self.spUUID, self.newImgUUID, self.newVolUUID)
        )

        self.assertTrue(self.agent.checkDiskImageSignature(volPath, imageFormat))

    def _exportExisting(self, collapse, force, imageFormat):
        self._createBaseStack(imageFormat)
        self._export(collapse, imageFormat)
        self._exportAgain(collapse, force, vdsc.COW_FORMAT)


    def _exportTemplateBeforeImage(self, collapse, imageFromat):
        self._createBaseStack(imageFromat)
        self._exportTemplate()
        self._export(collapse, imageFromat)
        if collapse:
            self._testImage(imageFromat)
        else:
            self._testImage(vdsc.COW_FORMAT)

    def _exportTemplateAfterImage(self, collapse, imageFormat):
        self._createBaseStack(imageFormat)
        self._export(collapse, imageFormat)
        self._exportTemplate()
        if collapse:
            self._testImage(imageFormat)
        else:
            self._testImage(vdsc.COW_FORMAT)

    def exportExistingWithoutForceRAW(self):
        self._exportExisting(False, False, vdsc.RAW_FORMAT)

    def exportExistingWithoutForceCOW(self):
        self._exportExisting(False, False, vdsc.COW_FORMAT)

    def exportExistingWithForceRAW(self):
        self._exportExisting(False, True, vdsc.RAW_FORMAT)

    def exportExistingWithForceCOW(self):
        self._exportExisting(False, True, vdsc.COW_FORMAT)

    def exportExistingWithCollapseWithForceCOW(self):
        self._exportExisting(True, True, vdsc.COW_FORMAT)

    def exportExistingWithCollapseWithForceRAW(self):
        self._exportExisting(True, True, vdsc.RAW_FORMAT)

    def exportExistingWithCollapseWithoutForceRAW(self):
        self._exportExisting(True, False, vdsc.RAW_FORMAT)

    def exportExistingWithCollapseWithoutForceCOW(self):
        self._exportExisting(True, False, vdsc.COW_FORMAT)

    def exportTemplateBeforeImageWithCollapseRAW(self):
        self._exportTemplateBeforeImage(True, vdsc.RAW_FORMAT)

    def exportTemplateBeforeImageWithCollapseCOW(self):
        self._exportTemplateBeforeImage(True, vdsc.COW_FORMAT)

    def exportTemplateBeforeImageRAW(self):
        self._exportTemplateBeforeImage(False, vdsc.RAW_FORMAT)

    def exportTemplateBeforeImageCOW(self):
        self._exportTemplateBeforeImage(False, vdsc.COW_FORMAT)

    def exportTemplateAfterImageRAW(self):
        self._exportTemplateAfterImage(False, vdsc.RAW_FORMAT)

    def exportTemplateAfterImageCOW(self):
        self._exportTemplateAfterImage(False, vdsc.COW_FORMAT)

    def exportTemplateAfterImageWithCollapseRAW(self):
        self._exportTemplateAfterImage(True, vdsc.RAW_FORMAT)

    def exportTemplateAfterImageWithCollapseCOW(self):
        self._exportTemplateAfterImage(True, vdsc.COW_FORMAT)

class ImageImportTests(ImageExportTests):
    def _testImageImported(self):
        volPath = self.assertVdscOK(
            self.client.getVolumePath(self.sdUUID2, self.spUUID, self.newImgUUID, self.newVolUUID)
        )['path']

        self.assertTrue(self.agent.checkDiskImageSignature(volPath, imageFormat))

    def _importTemplate(self):
        self.assertVdscOK(
            self.client.moveImage(self.spUUID, self.expSdUUID, self.sdUUID2, self.templateImgUUID,
            self.templateVmUUID, vdsc.COPYOP, False, False)
        )

    def _import(self, collapse, imageFormat):
        if not collapse:
            self.assertVdscOK(
                self.client.moveImage(self.spUUID, self.expSdUUID, self.sdUUID2, self.newImgUUID,
                self.newVmUUID, vdsc.COPYOP, False, False)
            )
        else:
            self.assertVdscOK(
                self.client.copyImage(self.expSdUUID, self.spUUID, self.templateVmUUID, self.newImgUUID,
                    self.newVolUUID, self.newImgUUID, self.newVolUUID, "I AM A COPY", self.sdUUID2,
                    vdsc.LEAF_VOL, imageFormat, vdsc.PREALLOCATED_VOL)
            )

    def ImportTemplateRAW(self):
        self.exportTemplateBeforeImageRAW()
        self._importTemplate()

    def ImportTemplateCOW(self):
        self.exportTemplateBeforeImageCOW()
        self._importTemplate()

    def ImportTemplateBeforeImageRAW(self):
        self.exportTemplateBeforeImageRAW()
        self._importTemplate()
        self._import(False, vdsc.RAW_FORMAT)

    def ImportTemplateBeforeImageCOW(self):
        self.exportTemplateBeforeImageCOW()
        self._importTemplate()
        self._import(False, vdsc.COW_FORMAT)

    def ImportWithoutBaseImageRAW(self):
        self.exportTemplateBeforeImageRAW()
        self.assertRaises(Exception, self._import, False, vdsc.RAW_FORMAT)

    def ImportWithoutBaseImageCOW(self):
        self.exportTemplateBeforeImageCOW()
        self.assertRaises(Exception, self._import, False, vdsc.COW_FORMAT)

    def ImportWithoutBaseImageWithCollapseRAW(self):
        self.exportTemplateBeforeImageRAW()
        self._import(True, vdsc.RAW_FORMAT)

    def ImportWithoutBaseImageWithCollapseCOW(self):
        self.exportTemplateBeforeImageCOW()
        self._import(True, vdsc.COW_FORMAT)

def suite():
    tests = {
         ImageExportTests : ["exportExistingWithForceRAW", "exportExistingWithForceCOW",
                             "exportExistingWithoutForceRAW", "exportExistingWithoutForceCOW",
                             "exportExistingWithCollapseWithForceRAW", "exportExistingWithCollapseWithForceCOW",
                             "exportTemplateAfterImageWithCollapseRAW", "exportTemplateAfterImageWithCollapseCOW",
                             "exportTemplateAfterImageRAW", "exportTemplateAfterImageCOW",
                             "exportTemplateBeforeImageRAW", "exportTemplateBeforeImageCOW",
                             "exportTemplateBeforeImageWithCollapseRAW", "exportTemplateBeforeImageWithCollapseCOW"
                             ],
        ImageImportTests : ["ImportTemplateBeforeImageRAW", "ImportTemplateBeforeImageCOW",
                            "ImportWithoutBaseImageRAW", "ImportWithoutBaseImageCOW",
                            "ImportTemplateRAW", "ImportTemplateCOW",
                            "ImportWithoutBaseImageWithCollapseRAW", "ImportWithoutBaseImageWithCollapseCOW",
                            ]
    }

    resSuite = ut.TestSuite()
    for testcase, methods in tests.iteritems():
        resSuite.addTests(map(testcase, methods))

    return resSuite

validateConfig = lambda cfg : vdst.validateSuiteConfig(suite(), cfg)
